package org.ci.blackberry.puzzle;
import java.util.Random;

import net.rim.device.api.math.Fixed32;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.Arrays;

import org.ci.blackberry.ui.BitmapButtonField45;

public class PuzzleApp extends UiApplication {

	public PuzzleApp() {
		pushScreen(new Scr());
	}

	public static void main(String[] args) {
		PuzzleApp app = new PuzzleApp();
		app.enterEventDispatcher();
	}
}

class Scr extends MainScreen {
	EncodedImage mImage = EncodedImage.getEncodedImageResource("image.jpg");
	BitmapField mImageField;
	Bitmap[] mSplittedImage;
	int mRows;
	int mCols;

	BitmapButtonField45[] mButtons;

	public Scr() {
		mImage = scaleImage(mImage, Display.getWidth(), Display.getHeight());
		add(mImageField = new BitmapField(mImage.getBitmap()));
	}

	void shufflePuzzle() {
		for (int i = 0; i < 1000; i++) {
			Random rnd = new Random();
			int index1 = rnd.nextInt(mButtons.length);
			int index2 = rnd.nextInt(mButtons.length);
			BitmapButtonField45 button1 = mButtons[index1];
			BitmapButtonField45 button2 = mButtons[index2];
			Arrays.remove(mButtons, button1);
			Arrays.remove(mButtons, button2);

			if (index1 > index2 + 1)
				index1--;

			Arrays.insertAt(mButtons, button2, index1);
			Arrays.insertAt(mButtons, button1, index2);
		}
		buildScreen(mRows, mCols);
	}

	void preparePuzzle(int rows, int cols) {
		mRows = rows;
		mCols = cols;
		mSplittedImage = splitImage(mImage.getBitmap(), mRows, mCols);
		mButtons = generateButtons(mRows, mCols);

		buildScreen(mRows, mCols);
	}

	private BitmapButtonField45[] generateButtons(int rows, int cols) {
		BitmapButtonField45[] result = new BitmapButtonField45[rows * cols];
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				int index = i * cols + j;
				Bitmap focused = getFocusedBitmap(mSplittedImage[index]);
				BitmapButtonField45 button = new BitmapButtonField45(
						mSplittedImage[index], focused);
				result[index] = button;
			}
		}
		return result;
	}

	private void buildScreen(int rows, int cols) {
		deleteAll();
		for (int i = 0; i < rows; i++) {
			HorizontalFieldManager hfm = new HorizontalFieldManager();
			add(hfm);
			for (int j = 0; j < cols; j++) {
				int index = i * cols + j;
				Manager manager = mButtons[index].getManager();
				if (null != manager)
					manager.deleteAll();
				hfm.add(mButtons[index]);
			}
		}
	}

	void resetPuzzle() {
		deleteAll();
		add(mImageField);
	}

	MenuItem mPreparePuzzle3x3 = new MenuItem("Puzzle 3x3", 0, 0) {
		public void run() {
			preparePuzzle(3, 3);
		};
	};

	MenuItem mPreparePuzzle6x6 = new MenuItem("Puzzle 6x6", 0, 0) {
		public void run() {
			preparePuzzle(6, 6);
		};
	};

	MenuItem mResetPuzzle = new MenuItem("Reset", 0, 0) {
		public void run() {
			resetPuzzle();
		};
	};

	MenuItem mShufflePuzzle = new MenuItem("Shuffle", 0, 0) {
		public void run() {
			shufflePuzzle();
		};
	};

	protected void makeMenu(Menu menu, int instance) {
		super.makeMenu(menu, instance);
		menu.add(mResetPuzzle);
		menu.add(mShufflePuzzle);
		menu.add(mPreparePuzzle3x3);
		menu.add(mPreparePuzzle6x6);
	}

	Bitmap[] splitImage(Bitmap bitmap, int rCnt, int cCnt) {
		Bitmap[] result = new Bitmap[rCnt * cCnt];
		int w = bitmap.getWidth() / cCnt;
		int h = bitmap.getHeight() / rCnt;
		for (int i = 0; i < rCnt; i++)
			for (int j = 0; j < cCnt; j++) {
				Bitmap bitmapPart = new Bitmap(w, h);
				Graphics g = new Graphics(bitmapPart);
				g.drawBitmap(0, 0, w, h, bitmap, w * j, h * i);
				result[i * cCnt + j] = bitmapPart;
			}
		return result;
	}

	Bitmap getFocusedBitmap(Bitmap bitmap) {
		int width = bitmap.getWidth();
		int height = bitmap.getHeight();
		Bitmap result = new Bitmap(width, height);
		Graphics g = new Graphics(result);
		g.drawBitmap(0, 0, width, height, bitmap, 0, 0);
		g.setColor(Color.WHITE);
		g.setGlobalAlpha(80);
		g.fillRect(0, 0, width, height);
		return result;
	}

	private EncodedImage scaleImage(EncodedImage image, int width, int height) {

		int currentWidthFixed32 = Fixed32.toFP(image.getWidth());
		int currentHeightFixed32 = Fixed32.toFP(image.getHeight());

		int requiredWidthFixed32 = Fixed32.toFP(width);
		int requiredHeightFixed32 = Fixed32.toFP(height);

		int scaleXFixed32 = Fixed32.div(currentWidthFixed32,
				requiredWidthFixed32);
		int scaleYFixed32 = Fixed32.div(currentHeightFixed32,
				requiredHeightFixed32);

		EncodedImage result = image.scaleImage32(scaleXFixed32, scaleYFixed32);
		return result;
	}
}